﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace Falafel.Controls.Dialogs
{
    public partial class ExceptionDialog
    {
        private List<Exception> Exceptions { get; set; }

        public ExceptionDialog(Exception exception, string title, string text = null, object userInfo = null)
        {
            InitializeComponent();
            Init(title, DialogBaseButton.Ok, DialogBaseType.Error, userInfo);

            SetException(exception, text);
            
            LayoutButtons();

            StackPanelCopy.Children.Add(GetCopyClipboardButton());
        }

        public void SetException(Exception exception, string text = null)
        {
            if (text == null)
            {
                TextBloxText.Text = exception.Message;
            }
            else
            {
                TextBloxText.Text = text;
            }
            
            Exception currentEx = exception;
            Exceptions = new List<Exception>();

            while (currentEx != null)
            {
                Exceptions.Add(currentEx);
                currentEx = currentEx.InnerException;
            }

            DataGridMessages.ItemsSource = GetExceptionMessages();

            IEnumerable<string> stackTraces = GetStackTraces();

            if (stackTraces.Count() == 0)
            {
                ExpanderStackTrace.Visibility = Visibility.Collapsed;
            }
            else
            {
                DataGridStackTrace.ItemsSource = stackTraces;
            }
        }

        private IEnumerable<string> GetExceptionMessages()
        {
            IList<string> messagesList = new List<string>();
            Exceptions.ForEach(ex => messagesList.Add(GetMessageFromException(ex)));

            return messagesList;
        }

        private IEnumerable<string> GetStackTraces()
        {
            var stackList = (from ex in Exceptions
                             where ex.StackTrace != null
                             select GetMessageFromException(ex) + Environment.NewLine + ex.StackTrace);

            return stackList;
        }

        private string GetMessageFromException(Exception exception)
        {
            string message = exception.Message;
            string exceptionType = exception.GetType().ToString();
            string exceptionClass;
            int idx = exceptionType.LastIndexOf('.');

            if (idx == -1)
            {
                exceptionClass = exceptionType;
            }
            else
            {
                exceptionClass = exceptionType.Substring(idx + 1);
            }
            
            return string.Format("{0}: {1}", exceptionClass, message);
        }

        private Button GetCopyClipboardButton()
        {
            Button aButton = new Button();
            aButton.HorizontalAlignment = HorizontalAlignment.Left;
            aButton.Name = "CopyClipboardButton";
            aButton.Content = "Copy to Clipboard";
            SetButtonAttributes(aButton, new Thickness(0, 0, 0, 0));
            aButton.Width = 130;
            aButton.Click += CopyClipboardButton_Click;

            return aButton;
        }

        private void CopyClipboardButton_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder buf = new StringBuilder();

            buf.Append("Message Trace:").Append(Environment.NewLine);
            GetExceptionMessages().ToList().ForEach(msg => buf.Append(msg).Append(Environment.NewLine));

            buf.Append(Environment.NewLine);
            buf.Append("Stack Trace:").Append(Environment.NewLine);

            IEnumerable<string> stackTraces = GetStackTraces();
            if (stackTraces.Count() == 0)
            {
                buf.Append("No stack traces available");
            }
            else
            {
                stackTraces.ToList().ForEach(st => buf.Append(st).Append(Environment.NewLine));
            }

            try
            {
                Clipboard.SetText(buf.ToString());
            }
            catch (SecurityException)
            {
                // ignore when the user chooses to not allow Silverlight access to the clipboard
            }
        }

        private void ExpanderMessages_Expanded(object sender, RoutedEventArgs e)
        {
            ExpanderStackTrace.IsExpanded = false;
        }

        private void ExpanderStackTrace_Expanded(object sender, RoutedEventArgs e)
        {
            ExpanderMessages.IsExpanded = false;
        }
    }
}

